package com.laomuji.android.mvvm.view

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.max

/**
 * 支持LTR和RTL的流式布局
 *
 * @author laomuji666
 * @since 2025/4/30
 */
class FlowLayoutManager : RecyclerView.LayoutManager() {
    private var recyclerView: RecyclerView? = null

    override fun onAttachedToWindow(view: RecyclerView) {
        super.onAttachedToWindow(view)
        this.recyclerView = view
    }

    private val isRTL: Boolean
        get() = recyclerView!!.layoutDirection == View.LAYOUT_DIRECTION_RTL

    override fun isAutoMeasureEnabled(): Boolean {
        return true
    }

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
            RecyclerView.LayoutParams.WRAP_CONTENT,
            RecyclerView.LayoutParams.WRAP_CONTENT
        )
    }

    override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
        detachAndScrapAttachedViews(recycler)

        val width = width

        var curX = if (isRTL) width else 0
        var curY = 0
        var lineHeight = 0

        for (i in 0..<itemCount) {
            val view = recycler.getViewForPosition(i)
            addView(view)
            measureChildWithMargins(view, 0, 0)
            val params = view.layoutParams as RecyclerView.LayoutParams

            val viewWidth = getDecoratedMeasuredWidth(view) + params.leftMargin + params.rightMargin
            val viewHeight =
                getDecoratedMeasuredHeight(view) + params.topMargin + params.bottomMargin

            val needWrap = if (isRTL) (curX - viewWidth < 0) else (curX + viewWidth > width)
            if (needWrap) {
                curY += lineHeight
                lineHeight = 0
                curX = if (isRTL) width else 0
            }

            val left: Int
            val right: Int
            if (isRTL) {
                right = curX - params.rightMargin
                left = right - getDecoratedMeasuredWidth(view)
                curX -= viewWidth
            } else {
                left = curX + params.leftMargin
                right = left + getDecoratedMeasuredWidth(view)
                curX += viewWidth
            }

            val top = curY + params.topMargin
            val bottom = top + getDecoratedMeasuredHeight(view)

            layoutDecorated(view, left, top, right, bottom)
            lineHeight = max(lineHeight.toDouble(), viewHeight.toDouble()).toInt()
        }
    }

    override fun canScrollVertically(): Boolean {
        return true
    }

    private var verticalOffset = 0

    override fun scrollVerticallyBy(
        dy: Int,
        recycler: RecyclerView.Recycler,
        state: RecyclerView.State
    ): Int {
        var travel = dy
        val totalHeight = totalContentHeight
        if (verticalOffset + dy < 0) {
            travel = -verticalOffset
        } else if (verticalOffset + dy > totalHeight - height) {
            travel = totalHeight - height - verticalOffset
        }

        verticalOffset += travel
        offsetChildrenVertical(-travel)
        return travel
    }

    private val totalContentHeight: Int
        get() {
            val width = width
            var curX = if (isRTL) width else 0
            var curY = 0
            var lineHeight = 0

            for (i in 0..<itemCount) {
                val view = getChildAt(i) ?: continue

                val params = view.layoutParams as RecyclerView.LayoutParams
                val viewWidth =
                    getDecoratedMeasuredWidth(view) + params.leftMargin + params.rightMargin
                val viewHeight =
                    getDecoratedMeasuredHeight(view) + params.topMargin + params.bottomMargin

                val needWrap = if (isRTL) (curX - viewWidth < 0) else (curX + viewWidth > width)
                if (needWrap) {
                    curY += lineHeight
                    lineHeight = 0
                    curX = if (isRTL) width else 0
                }

                curX += if (isRTL) -viewWidth else viewWidth
                lineHeight = max(lineHeight.toDouble(), viewHeight.toDouble()).toInt()
            }

            curY += lineHeight
            return curY
        }

    override fun scrollToPosition(position: Int) {
        verticalOffset = 0
        requestLayout()
    }

    override fun smoothScrollToPosition(
        recyclerView: RecyclerView,
        state: RecyclerView.State,
        position: Int
    ) {
        scrollToPosition(position)
    }
}
